#pragma once
#include "compile.hpp"
#include "runner.hpp"
#include "../comm/Log.hpp"
#include "../comm/util.hpp"
#include <jsoncpp/json/json.h>
#include <unistd.h>
#include"../comm/httplib.h"
#include <signal.h>
using namespace std;
namespace ns_compile_and_run
{
    using namespace nu_util;
    using namespace ns_log;
    using namespace ns_compile;
    using namespace ns_runner;
    class CompileAndRun
    {
    public:
        // code>0;进程收到了信号导致崩溃（运行报错）
        // code<0；整个过程非运行错误（代码为空，编译错误）
        // code=0；进程成功运行
        // -待完善
        static std::string CodeToDesc(int code, const std::string file_name)
        {
            std::string desc;
            switch (code)
            {
            case 0:
                desc = "编译运行成功";
                break;
            case -1:
                desc = "提交的代码是空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                FileUtil::ReadFile(PathUtil::CompilerError(file_name), &desc, true);
                break;
            case SIGABRT: // 6
                desc = "内存超过范围";
                break;
            case SIGXCPU:
                desc = "CPU使用超时";
                break;
            case SIGFPE: // 8
                desc = "浮点数溢出";
                break;
            default:
                desc = "未知:" + std::to_string(code);
                break;
            }
            return desc;
        }
        static void RemoveTempFile(const std::string &file_name)
        {
            std::string _src = PathUtil::Src(file_name);
            if (FileUtil::IsFileExists(_src))
                unlink(_src.c_str());
            std::string _compile_error = PathUtil::CompilerError(file_name);
            if (FileUtil::IsFileExists(_compile_error))
                unlink(_compile_error.c_str());
            std::string _execute = PathUtil::Exe(file_name);
            if (FileUtil::IsFileExists(_execute))
                unlink(_execute.c_str());
            std::string _stdout = PathUtil::Stdout(file_name);
            if (FileUtil::IsFileExists(_stdout))
                unlink(_stdout.c_str());
            std::string _stdin = PathUtil::Stdin(file_name);
            if (FileUtil::IsFileExists(_stdin))
                unlink(_stdin.c_str());
            std::string _stderr = PathUtil::Stderr(file_name);
            if (FileUtil::IsFileExists(_stderr))
                unlink(_stderr.c_str());
        }
        /******************************
         * 输入；
         * code；用户提交的代码
         * input；用户给自己提交的代码对应的输入，不做处理，自己扩展
         * cpu_limit;时间要求
         * mem_limit；空间要求
         * 输出；
         * 必填
         * status；状态码
         * status>0运行错误
         * status<0编译错误和运行错误
         * status=0 程序运行成功
         * reason；请求结果
         * 选填；
         * stdout；我的程序运行结果
         * stderr；我的程序运行万的错误结果
         * 参数
         * in_json:{"code":"#include...","input":"","cpu_limit":1,"mem_limit":"20"}
         * out_json:{"status":"0","reason":"","stdout":"","stderr":""}
         * *****************************
         */
        static void Start(const std::string &in_json, std::string *out_json)
        {
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();
            int status_code = 0;
            std::string outsting;
            Json::Value out_value;
            int run_result = 0;
            std::string file_name = FileUtil::UniqFileName();
            if (code.size() == 0)
            {
                // //最后在处理差错问题
                // out_value["statue"]=1;//代码为空
                // out_value["reason"]="用户提交的代码是空的";
                // //序列化过程
                status_code = -1;
                goto END;
            }
            // 形成的文件名具有唯一性，没有目录和后缀
            // 毫米级时间戳+原子性递增唯一值:来保证唯一名
            // 形成临时src文件
            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
            {
                // out_value["statue"]=2;//未知错误
                // out_value["reason"]="代码发生了未知错误";
                // //序列号过程
                status_code = -1;
                goto END;
            }
            if (!Compiler::Compile(file_name))
            {
                // //编译失败
                // out_value["status"]=3;//代码编译时发生了错误
                // out_value["reason"]=FileUtil::ReadFile(PathUtil::Stderr(file_name));
                status_code = -3;
                goto END;
            }
            run_result = Runner::Run(file_name, cpu_limit, mem_limit);
            if (run_result < 0)
            {
                //  out_value["statue"]=-2;//未知错误
                // out_value["reason"]="代码发生了未知错误";
                // //序列号过程
                status_code = -2;
                goto END;
            }
            else if (run_result > 0)
            {
                // out_value["status"]=code;//运行奔溃了
                // out_value["reason"]=SignoToDesc(code);//将信息转换成报错的原因
                // //序列化过程
                status_code = run_result;
                goto END;
            }
            else
            {
                // 运行成功
                status_code = 0;
                goto END;
            }
        END:
            out_value["statue"] = status_code;
            out_value["reason"] = CodeToDesc(status_code, file_name);

            if (status_code == 0)
            {
                std::string _stdout;
                std::string _stderr;
                // 整个过程全部成功
                FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
                FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr, true);
                out_value["stdout"] = _stdout;
                out_value["stderr"] = _stderr;
            }
            std::string _stdout;
            std::string _stderr;
            // 整个过程全部成功
            FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
            FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr, true);
            out_value["stdout"] = _stdout;
            out_value["stderr"] = _stderr;
            Json::StyledWriter write;
            *out_json = write.write(out_value);
            RemoveTempFile(file_name);
        }
    };
}